package com.xbongbong.saas.help.workflow;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ReceiveStatusEnum;
import com.xbongbong.pro.enums.RefundStatusEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.product.pojo.ProductSavePojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductStockEntity;
import com.xbongbong.saas.domain.entity.ProductStockUpdateEntity;
import com.xbongbong.saas.domain.entity.ProductWarehouseEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.InventoryEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductionOrderEntityExt;
import com.xbongbong.saas.domain.entity.ext.PurchaseEntityExt;
import com.xbongbong.saas.domain.entity.ext.RefundEntityExt;
import com.xbongbong.saas.domain.entity.ext.TransferEntityExt;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.InstockEnum;
import com.xbongbong.saas.enums.business.InventoryEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.ProductionOrderEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.business.ReturnEnum;
import com.xbongbong.saas.enums.business.TransferEnum;
import com.xbongbong.saas.enums.dictionary.AllInBoundEnum;
import com.xbongbong.saas.enums.dictionary.InventoryNewStatusEnum;
import com.xbongbong.saas.enums.dictionary.InventoryStatusEnum;
import com.xbongbong.saas.enums.dictionary.PurchaseStatusEnum;
import com.xbongbong.saas.enums.dictionary.ReturnStatusEnum;
import com.xbongbong.saas.enums.dictionary.TransferNewStatusEnum;
import com.xbongbong.saas.enums.dictionary.TransferStatusEnum;
import com.xbongbong.saas.enums.product.InstockProductEnum;
import com.xbongbong.saas.enums.subform.ContractProductSubFormEnum;
import com.xbongbong.saas.help.BatchKeyHelp;
import com.xbongbong.saas.help.SaasProductHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.ContractProductModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.InventoryModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductStockModel;
import com.xbongbong.saas.model.ProductWarehouseModel;
import com.xbongbong.saas.model.ProductionOrderModel;
import com.xbongbong.saas.model.PurchaseModel;
import com.xbongbong.saas.model.RefundModel;
import com.xbongbong.saas.model.TransferModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 *
 * @author 魏荣杰
 *
 */
@Component
@Slf4j
public class InstockHelp {

    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private ContractProductModel contractProductModel;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private ContractModel contractModel;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private PurchaseModel purchaseModel;
    @Resource
    private RefundModel refundModel;
    @Resource
    private InventoryModel inventoryModel;
    @Resource
    private TransferModel transferModel;
    @Resource
    private ProductionOrderModel productionOrderModel;
    @Resource
    private PurchaseHelp purchaseHelp;
    @Resource
    private RefundSaveHelp refundSaveHelp;
    @Resource
    private TransferHelp transferHelp;
    @Resource
    private ProductionOrderHelp productionOrderHelp;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private ProductStockModel productStockModel;
    @Resource
    private ProductWarehouseModel productWarehouseModel;
    @Resource
    private ProductModel productModel;
    @Resource
    private WorkflowProductHelp workflowProductHelp;


    /**
     * 退货入库单修复合同成本
     * @param corpid
     * @param refIdSet
     * @throws XbbException
     */
    public void afterSaveRefundInstock4ContractCost(String corpid, Set<Long> refIdSet, boolean isNew, JSONArray productJsonArray) throws XbbException {
        Boolean isJxcUse = paasAppModel.validateAppEnable(null, XbbRefTypeEnum.JXC.getAlias(), SaasMarkEnum.SAAS.getCode(), corpid);
        // 退货入库单的源单据是退货退款单
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        if (Objects.nonNull(refIdSet) && !refIdSet.isEmpty()) {
            boolQueryBuilder.filter(termsQuery(StringConstant.DATA_ID, refIdSet));
        }
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        sourceBuilder.query(boolQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);
        // 源合同ID
        List<Long> contractIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntity entity : esEntities.getContent()) {
            JSONObject data = entity.getData();
            Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.CONTRACT_ID.getAttr(), 0L);
            contractIdIn.add(contractId);
        }

        // 查询出所有关联原合同的退货金额(一对多)
        Map<Long, Double> allContractCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与红冲合同对应map
        Map<Long, List<Long>> contractIdAndRedContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与入库单对应map
        Map<Long, List<Long>> contractIdAndInstockIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        BoolQueryBuilder oldQueryBuilder = boolQuery();
        oldQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        oldQueryBuilder.filter(termsQuery(RefundEnum.getEsAttr4Keyword(RefundEnum.CONTRACT_ID),contractIdIn));
        oldQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        oldQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(oldQueryBuilder);
        PageRequest page = EsUtil.setPage(builder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest search = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        search.source(builder);
        XbbAggregatedPage<PaasFormDataEntity> entities = xbbElasticsearchRestTemplate.queryForPages(page, search, PaasFormDataEntity.class);
        for (PaasFormDataEntity entity : entities.getContent()) {
            JSONObject data = entity.getData();
            Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.CONTRACT_ID.getAttr(), 0L);
            Double returnCost = FastJsonHelper.getDoubleOrDefaultFromFormData(data, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);

            // 统计所有的退货金额
            if(allContractCostMap.containsKey(contractId)){
                Double cost = allContractCostMap.get(contractId) == null ? 0D : allContractCostMap.get(contractId);
                returnCost = Arith.add(returnCost, cost);
                allContractCostMap.put(contractId, returnCost);
            } else {
                allContractCostMap.put(contractId, returnCost);
            }

            // 合同与红冲合同对应关系
            Long redConId = data.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
            if(contractIdAndRedContractMap.containsKey(contractId)){
                List<Long> redConIdList = contractIdAndRedContractMap.get(contractId) == null ? new ArrayList<>() : contractIdAndRedContractMap.get(contractId);
                List<Long> idList = new ArrayList<>(redConIdList);
                idList.add(redConId);
                contractIdAndRedContractMap.put(contractId, idList);
            } else {
                contractIdAndRedContractMap.put(contractId, Arrays.asList(redConId));
            }

            // 合同与入库单对应关系
            JSONArray instockIdArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, RefundEnum.INSTOCK_ID.getAttr(), new JSONArray());
            if(!instockIdArr.isEmpty()){
                List<Long> instocks = instockIdArr.toJavaList(Long.class);
                if(contractIdAndInstockIdMap.containsKey(contractId)){
                    List<Long> instockList = contractIdAndInstockIdMap.get(contractId) == null ? new ArrayList<>() : contractIdAndInstockIdMap.get(contractId);
                    List<Long> idList = new ArrayList<>(instockList);
                    idList.addAll(instocks);
                    contractIdAndInstockIdMap.put(contractId, idList);
                } else {
                    contractIdAndInstockIdMap.put(contractId, instocks);
                }
            }
        }

        // 查询出所有关联原合同的出库单
        Map<Long, List<Long>> allContractOutMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 所有对应的合同实体

        BoolQueryBuilder entityQueryBuilder = boolQuery();
        entityQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        entityQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), contractIdIn));
        entityQueryBuilder.filter(termQuery("del", 0));
        entityQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT.getType()));
        SearchSourceBuilder conBuilder = new SearchSourceBuilder();
        conBuilder.query(entityQueryBuilder);
        PageRequest conPage = EsUtil.setPage(conBuilder, 1, 1);
        SearchRequest conSearch = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
        conSearch.source(conBuilder);
        XbbAggregatedPage<ContractEntityExt> conEsEntities = xbbElasticsearchRestTemplate.queryForPages(conPage, conSearch, ContractEntityExt.class);

        // 所有合同的实体
        Map<Long, ContractEntityExt> conIdAndConMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractEntityExt entity : conEsEntities.getContent()) {
            Long contractId = entity.getDataId();
            conIdAndConMap.put(contractId, entity);

            JSONObject data = entity.getData();
            List<Long> outstockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, ContractEnum.OUTSTOCK_ID.getAttr(), new JSONArray()).toJavaList(Long.class);

            if(allContractOutMap.containsKey(contractId)){
                List<Long> outIdList = allContractOutMap.get(contractId) == null ? new ArrayList<>() : allContractOutMap.get(contractId);
                List<Long> outIdIn = new ArrayList<>(outIdList);
                outIdIn.addAll(outstockIdList);
                allContractOutMap.put(contractId, outIdIn);
            } else {
                allContractOutMap.put(contractId, outstockIdList);
            }
        }

        Map<Long, Double> updateInstockCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Map<Long, Double>> numMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(Long contractId : contractIdIn){
            Double jxc2UpdateInstockCost = BasicConstant.ZERO_DOUBLE;
            // 查询该合同对应所有入库单的产品
            List<Long> instockList = contractIdAndInstockIdMap.get(contractId) == null ? new ArrayList<>() : contractIdAndInstockIdMap.get(contractId);
            //入库单的产品id及其数量
            Map<Long, Double> instockProductIdAndNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(!instockList.isEmpty()){
                Map<String,Object> instockProductParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                instockProductParam.put("corpid", corpid);
                instockProductParam.put("instockIdIn",instockList);
                instockProductParam.put("del", 0);
                List<InstockProductEntity> instockProductEntityList = instockProductModel.findEntitys(instockProductParam);
                for(InstockProductEntity instockPro : instockProductEntityList){
                    // 新数据计算，直接计算所有该合同所有入库单的成本
                    Double productNum = instockPro.getProductNum() == null ? 0D : Math.abs(instockPro.getProductNum());
                    Double productCost = instockPro.getCost() == null ? 0D : instockPro.getCost();
                    jxc2UpdateInstockCost = Arith.add(jxc2UpdateInstockCost, Arith.mul(productNum, productCost));

                    // 统计入库单每一件产品的数量
                    Long productId = instockPro.getProductId();
                    if(instockProductIdAndNum.containsKey(productId)){
                        Double inNum = instockProductIdAndNum.get(productId) == null ? BasicConstant.ZERO_DOUBLE : instockProductIdAndNum.get(productId);
                        Double countNum = Arith.add(inNum, productNum);
                        instockProductIdAndNum.put(productId, countNum);
                    } else {
                        instockProductIdAndNum.put(productId, productNum);
                    }
                }
            }

            // 新建数据还没有入库，直接取前端
            if(isNew && productJsonArray != null){
                for (int i = 0; i < productJsonArray.size(); i++) {
                    JSONObject jsonObject = productJsonArray.getJSONObject(i);
                    Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
                    Double productNum = jsonObject.getDouble(InstockProductEnum.NUM.getAttr());
                    Double productCost = Objects.isNull(jsonObject.getDouble(InstockProductEnum.COST.getAttr())) ? 0D : jsonObject.getDouble(InstockProductEnum.COST.getAttr());

                    // 计算成本
                    jxc2UpdateInstockCost = Arith.add(jxc2UpdateInstockCost, Arith.mul(productNum, productCost));
                    // 统计入库单每一件产品的数量
                    if(instockProductIdAndNum.containsKey(pageProductId)){
                        Double inNum = instockProductIdAndNum.get(pageProductId) == null ? BasicConstant.ZERO_DOUBLE : instockProductIdAndNum.get(pageProductId);
                        Double countNum = Arith.add(inNum, productNum);
                        instockProductIdAndNum.put(pageProductId, countNum);
                    } else {
                        instockProductIdAndNum.put(pageProductId, productNum);
                    }
                }
            }
            updateInstockCostMap.put(contractId, jxc2UpdateInstockCost);
            numMap.put(contractId, instockProductIdAndNum);
        }

        // 合同与红冲合同退货产品成本对应map
        Map<Long, Double> contractIdAndCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 查询所有的红冲合同
        Iterator entries = contractIdAndRedContractMap.entrySet().iterator();
        while(entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            Long key = (Long) entry.getKey();
            List<Long> redConIdList = contractIdAndRedContractMap.get(key);
            Double costAmount = BasicConstant.ZERO_DOUBLE;
            if(redConIdList.size() > 0) {
                Map<Long, Double> productIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Object> redParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                redParam.put("corpid", corpid);
                redParam.put("contractIdIn",redConIdList);
                redParam.put("del", 0);
                // 拿到红冲合同的所有产品
                List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(redParam);
                //判断是否是新旧数据
                boolean sourceDoc = false;
                for(ContractProductEntity entity : contractProductEntityList){
                    JSONObject data = entity.getData();
                    if (data.containsKey(SelectProductEnum.SOURCE_DOC.getAttr())) {
                        sourceDoc = true;
                        break;
                    }
                }
                // 新数据直接使用累加结果
                if(sourceDoc){
                    Double jxc2UpdateInstockCost = updateInstockCostMap.get(key) == null ? BasicConstant.ZERO_DOUBLE : updateInstockCostMap.get(key);
                    contractIdAndCostMap.put(key, jxc2UpdateInstockCost);
                    break;
                }

                //-----------------------旧数据处理---------------------------
                // 退货产品ID以及对应的数量
                for(ContractProductEntity entity : contractProductEntityList){
                    Long pageProductId = entity.getProductId();
                    Double productNum = entity.getProductNum() == null ? 0D : Math.abs(entity.getProductNum());
                    if(productIdAndNumMap.containsKey(pageProductId)){
                        Double num = productIdAndNumMap.get(pageProductId) == null ? 0D : productIdAndNumMap.get(pageProductId);
                        productNum = Arith.add(productNum, num);
                    }
                    productIdAndNumMap.put(pageProductId, productNum);
                }

                List<Long> outstockIdList = allContractOutMap.get(key);
                Map<Long, Double> instockProductIdAndNum = numMap.get(key);
                if(outstockIdList != null && !instockProductIdAndNum.isEmpty() && isJxcUse){
                    Map<String,Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    outstockParam.put("corpid", corpid);
                    outstockParam.put("del", DelEnum.NORMAL.getDel());
                    outstockParam.put("outstockIdIn", outstockIdList);
                    List<OutstockProductEntity> outstockProductList = outstockProductModel.findEntitys(outstockParam);
                    Map<Long, OutstockProductEntity> outstockProductEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 算出每个产品对应的成本
                    Map<Long, Double> productIdAndCost = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 所有的出库记录
                    for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                        Long productId = outstockProductEntity.getProductId();
                        Double productNum = outstockProductEntity.getProductNum() == null ? 0D : outstockProductEntity.getProductNum();
                        Double productCost = outstockProductEntity.getCost() == null ? 0D : outstockProductEntity.getCost();
                        // 将所有记录的相同产品的平均成本求出
                        if (outstockProductEntityMap.containsKey(productId)) {
                            OutstockProductEntity oldOutstockProductEntity = outstockProductEntityMap.get(productId);
                            Double oldProductNum = oldOutstockProductEntity.getProductNum() == null ? 0D : oldOutstockProductEntity.getProductNum();
                            Double oldProductCost = oldOutstockProductEntity.getCost() == null ? 0D : oldOutstockProductEntity.getCost();
                            // 上一次的产品总成本
                            Double oldCost = Arith.mul(oldProductNum, oldProductCost);
                            // 这一次的产品总成本
                            Double newCost = Arith.mul(productNum, productCost);
                            // (上一次的产品总成本+这一次的产品总成本)/两次的总数量
                            productCost = Arith.div(Arith.add(oldCost, newCost), Arith.add(oldProductNum, productNum), 2);
                        }
                        outstockProductEntityMap.put(productId, outstockProductEntity);
                        productIdAndCost.put(productId, productCost);
                    }
                    // 遍历入库产品
                    Iterator iterator = instockProductIdAndNum.keySet().iterator();
                    while (iterator.hasNext()) {
                        Long id = Long.valueOf(iterator.next().toString());
                        Double productNum = instockProductIdAndNum.get(id);
                        if(productIdAndCost.containsKey(id)){
                            costAmount = Arith.add(costAmount, Arith.mul(productNum, productIdAndCost.get(id)));
                        }
                    }
                } else if(!isJxcUse){
                    // 不开启进销存是直接查询原合同关联产品表的成本*红冲合同产品表的产品数量(退货产品数量)
                    BoolQueryBuilder proQueryBuilder = boolQuery();
                    proQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                    proQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                    proQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.TYPE), 201));
                    proQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.CONTRACT_ID), key));
                    proQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT.getType()));
                    List<String> fieldList = Arrays.asList(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.CONTRACT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_NUM), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.COST));
                    List<PaasFormDataEntity> list =  esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT, proQueryBuilder, PaasFormDataEntity.class, fieldList);
                    if(list.size() > 0) {
                        List<ContractProductEntity> contractProductEntities = transferSubFormHelper.transferFormDataToContractProductList(list);
                        for (ContractProductEntity contractProductEntity : contractProductEntities) {
                            Long productId = contractProductEntity.getProductId();
                            Double cost = contractProductEntity.getCost() == null ? 0D : contractProductEntity.getCost();
                            if(productIdAndNumMap.containsKey(productId)){
                                Double productCost = Arith.mul(cost, productIdAndNumMap.get(productId));
                                costAmount = Arith.add(costAmount, productCost);
                            }
                        }
                    }
                }
            }
            contractIdAndCostMap.put(key, costAmount);
        }
        List<UpdateDataEntity> updateList = new ArrayList<>();
        for(Long contractId : contractIdIn){
            ContractEntityExt contractEntityExt = conIdAndConMap.get(contractId);
            JSONObject contractData = contractEntityExt.getData();
            JSONObject updateContractData = new JSONObject();

            BoolQueryBuilder outQueryBuilder = boolQuery();
            outQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            outQueryBuilder.filter(termQuery("del", 0));
            outQueryBuilder.filter(termQuery("data." + OutstockEnum.TYPE.getAttr(), OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()));
            outQueryBuilder.filter(termsQuery("data." + OutstockEnum.REF_ID.getAttr(), Arrays.asList(contractId)));
            outQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
            outQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_OUTSTOCK.getType()));
            List<PaasFormDataEntityExt> outstockList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, outQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(OutstockEnum.getAttrConnectData(OutstockEnum.REF_ID), FieldTypeEnum.DATAID.getAlias()));

            // 根据出库单获取对应的产品
            List<Long> dataIdIn = new ArrayList<>();
            outstockList.forEach(outstock -> dataIdIn.add(outstock.getDataId()));
            Map<String, Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            outstockParam.put("corpid", corpid);
            outstockParam.put("del", 0);
            outstockParam.put("outstockIdIn", dataIdIn);
            List<OutstockProductEntity> outstockAllProductList = outstockProductModel.findEntitys(outstockParam);

            // 合同和关联的出库单的对应关系
            Map<Long, List<Long>> contractOutstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> outstockIdList = contractOutstockMap.get(contractId);
            if (outstockIdList == null) {
                outstockIdList = new ArrayList<>();
            }
            for (PaasFormDataEntityExt outstock : outstockList) {
                Long refConId = outstock.getData().getLong(OutstockEnum.REF_ID.getAttr());
                if (Objects.equals(contractId, refConId)) {
                    outstockIdList.add(outstock.getDataId());
                }
            }
            contractOutstockMap.put(contractId, outstockIdList);

            // 合同和出库产品的对应关系
            Map<Long, List<OutstockProductEntity>> contractOutstockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> outstockIdLists = contractOutstockMap.get(contractId);
            List<OutstockProductEntity> outstockProductEntityList = contractOutstockProductMap.get(contractId);
            if (outstockProductEntityList == null) {
                outstockProductEntityList = new ArrayList<>();
            }
            for (OutstockProductEntity outstockProductEntity : outstockAllProductList) {
                Long outstockId = outstockProductEntity.getOutWarehouseId();
                if (outstockIdLists.contains(outstockId)) {
                    outstockProductEntityList.add(outstockProductEntity);
                }
            }
            contractOutstockProductMap.put(contractId, outstockProductEntityList);

            // 合同和关联产品的对应关系
            List<ContractProductEntity> contractProList = contractProductModel.getContractProductByContractIdIn(corpid, Arrays.asList(contractId));
            Map<Long, List<ContractProductEntity>> contractProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<ContractProductEntity> contractProductEntityList = contractProductMap.get(contractId);
            if (contractProductEntityList == null) {
                contractProductEntityList = new ArrayList<>();
            }
            for (ContractProductEntity contractProductEntity : contractProList) {
                if (Objects.equals(contractProductEntity.getContractId(), contractId)) {
                    contractProductEntityList.add(contractProductEntity);
                }
            }
            contractProductMap.put(contractId, contractProductEntityList);

            // 整理数据
            List<OutstockProductEntity> outstockProductList = contractOutstockProductMap.get(contractId);
            List<ContractProductEntity> contractProductList = contractProductMap.get(contractId);

            // 计算合同出库成本：SUM（已出库产品数量*出库产品成本）
            double realCost = 0D;
            boolean isOld = false;
            // 合并的出库产品数量MAP
            Map<Long, Double> outstockProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 行对应数量
            Map<Long, Double> lineProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                if (Objects.isNull(outstockProductEntity.getRefProductId())) {
                    isOld = true;
                }
                Long productId = outstockProductEntity.getProductId();
                Double productNum = outstockProductEntity.getProductNum();
                productNum = productNum == null ? 0D : productNum;
                Double cost = outstockProductEntity.getCost();
                cost = cost == null ? 0D : cost;
                realCost = Arith.add(realCost, Arith.mul(productNum, cost));
                if (outstockProductNumMap.containsKey(productId)) {
                    outstockProductNumMap.put(productId, Arith.add(outstockProductNumMap.get(productId), productNum));
                } else {
                    outstockProductNumMap.put(productId, productNum);
                }
                if (!isOld) {
                    Long refProductId = outstockProductEntity.getRefProductId();
                    if (lineProductNumMap.containsKey(refProductId)) {
                        lineProductNumMap.put(refProductId, Arith.add(lineProductNumMap.get(refProductId), productNum));
                    } else {
                        lineProductNumMap.put(refProductId, productNum);
                    }
                }
            }

            // 算出合同中每种产品的平均价
            Map<Long, String> avgCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (ContractProductEntity contractProductEntity : contractProductList) {
                Long productId = contractProductEntity.getProductId();
                Double productNum = contractProductEntity.getProductNum() == null ? 0D : Math.abs(contractProductEntity.getProductNum());
                if (isOld) {
                    if (avgCostMap.containsKey(productId)) {
                        // map中已经有相同产品，需要计算平均值
                        String productInfo = avgCostMap.get(productId);
                        String[] split = productInfo.split(",");
                        Double preCost = StringUtil.toDouble((split[0]), 0D);
                        Double preNum = StringUtil.toDouble((split[1]), 0D);
                        Double nowCost = SaasProductHelp.calculateCost(preNum, preCost, productNum, contractProductEntity.getCost(), 1);
                        Double nowNum = Arith.add(preNum, productNum);
                        avgCostMap.put(productId, nowCost + "," + nowNum);
                    } else {
                        // 将产品id为key，合同产品平均价和数量拼接字符串为value存入map中
                        String productInfo = contractProductEntity.getCost() + "," + productNum;
                        avgCostMap.put(productId, productInfo);
                    }
                } else if (lineProductNumMap.containsKey(contractProductEntity.getId())) {
                    // 分行已出库数量计算
                    contractProductEntity.setContractOutstockNum(lineProductNumMap.get(contractProductEntity.getId()));
                }
            }
            double estimateCost = 0D;
            if (isOld) {
                // 老数据合同预估成本计算
                for (ContractProductEntity contractProductEntity : contractProductList) {
                    String productInfo = avgCostMap.get(contractProductEntity.getProductId());
                    if (org.apache.commons.lang.StringUtils.isEmpty(productInfo)) {
                        continue;
                    }
                    String[] productInfos = productInfo.split(",");
                    if (outstockProductNumMap.containsKey(contractProductEntity.getProductId())) {
                        if (Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())) > 0) {
                            estimateCost = Arith.add(estimateCost, Arith.mul(Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())), StringUtil.toDouble((productInfos[0]), 0D)));
                        }
                    } else {
                        estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getProductNum(), StringUtil.toDouble((productInfos[0]), 0D)));
                    }
                }
            } else {
                // 新数据合同预估成本计算
                for (ContractProductEntity contractProductEntity : contractProductList) {
                    if (Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum()) > 0) {
                        estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getCost(), Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum())));
                    }
                }
            }

            // 合同成本 = 合同产品成本 - 退货产品成本（入库单的产品成本：新数据用入库单的成本，旧数据用出库单的平均成本）+ 其他费用
            Double surchargeAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractData, ContractEnum.OTHER_EXPENSE.getAttr(), BasicConstant.ZERO_DOUBLE);
            Double contractCost;
            if(contractIdAndCostMap.containsKey(contractId)){
                Double cost = contractIdAndCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : contractIdAndCostMap.get(contractId);
                contractCost = Arith.sub(Arith.add(Arith.add(estimateCost, realCost), surchargeAmount), cost);
            } else {
                contractCost = Arith.add(Arith.add(estimateCost, realCost), surchargeAmount);
            }
            updateContractData.put(ContractEnum.CONTRACT_COST.getAttr(), Arith.round(contractCost, 2));

            //合同毛利 = 合同金额 - 退货金额（关联计算）- 合同成本（同上）
            Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractData, ContractEnum.AMOUNT.getAttr(), 0D);
            Double grossProfit;
            if(allContractCostMap.containsKey(contractId)){
                Double cost = allContractCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : allContractCostMap.get(contractId);
                grossProfit = Arith.sub(Arith.sub(amount, contractCost), cost);
            } else {
                grossProfit = Arith.sub(amount, contractCost);
            }
            updateContractData.put(ContractEnum.GROSS_PROFIT.getAttr(), Arith.round(grossProfit, 2));

            // 合同毛利率
            if (Double.compare(amount, BasicConstant.ZERO_DOUBLE) != 0) {
                updateContractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), Arith.round(Arith.div(grossProfit, amount), 4));
            } else {
                updateContractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
            }

            // 现金毛利 = 合同已收款金额 - 合同成本（同上）
            Double finishAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractData, ContractEnum.FINISH_AMOUNT.getAttr(), 0D);
            Double cashProfit = Arith.sub(finishAmount, contractCost);
            updateContractData.put(ContractEnum.CASH_PROFIT.getAttr(), cashProfit);
            // 现金毛利率
            if (Double.compare(finishAmount, BasicConstant.ZERO_DOUBLE) != 0) {
                updateContractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), Arith.round(Arith.div(cashProfit, finishAmount), 2));
            } else {
                updateContractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
            }
            UpdateDataEntity updateData = ExplainUtil.getUpdateData(contractEntityExt.getId(), updateContractData, corpid);
            updateList.add(updateData);
        }
        if (CollectionsUtil.isNotEmpty(updateList)) {
            contractModel.updateBatch(updateList, corpid);
        }
    }


    public void setIntstockDocumentsNew(String corpid, JSONObject data, PaasFormDataEntity paasFormDataEntity) throws XbbException {
        Long instockId = paasFormDataEntity.getId();
        Long refId = data.getLong(InstockEnum.REF_ID.getAttr());
        Integer instockType = FastJsonHelper.getIntegerFromFormData(data, InstockEnum.TYPE.getAttr());
        InstockTypeEnum instockTypeEnum = InstockTypeEnum.getByCode(instockType);
        JSONArray productJsonArray = paasFormDataEntity.getData().getJSONArray(InstockEnum.PRODUCT.getAttr());
        List<ProductSavePojo> productSavePojoList = new ArrayList<>();
        productJsonArray.forEach(item -> {
            JSONObject json = (JSONObject) item;
            ProductSavePojo productSavePojo = new ProductSavePojo();
            productSavePojo.setId(json.getLong(InstockProductEnum.PRODUCT.getAttr()));
            productSavePojo.setParentId(json.getLong(ProductEnum.PARENT_ID.getSaasAttr()));
            productSavePojo.setNum(json.getDouble(InstockProductEnum.NUM.getAttr()));
            if (Objects.nonNull(json.getLong(BusinessConstant.REF_PRODUCT_ID))) {
                productSavePojo.setRefProductId(json.getLong(BusinessConstant.REF_PRODUCT_ID));
            }
            productSavePojoList.add(productSavePojo);
        });
        PaasFormDataEntityExt paasFormDataEntityExt;
        boolean allInBound;
        switch (instockTypeEnum){
            case PURCHASE_INSTOCK:
                paasFormDataEntityExt = purchaseModel.getByKey(refId,corpid);
                if (Objects.isNull(paasFormDataEntityExt)) {
                    return;
                }
                PurchaseEntityExt purchaseEntityExt = new PurchaseEntityExt();
                BeanUtil.copyProperties(paasFormDataEntityExt,purchaseEntityExt);
                JSONObject purchaseData = purchaseEntityExt.getData();
                //有ref_product_id的为新数据
                allInBound = purchaseHelp.judgePurchaseAllInBound(instockId,refId,corpid,productSavePojoList);
                purchaseData.put(PurchaseEnum.RECEIVE_STATUS.getAttr(),ReceiveStatusEnum.PARTIAL.getCode());
                //产品全部出库不管要不要审批直接改对应单据状态，防止此采购合同再次被选
                if (allInBound) {
                    //已全部入库
                    purchaseData.put(PurchaseEnum.ALL_INCOMING.getAttr(), AllInBoundEnum.ALL_IN.getCode());
                    purchaseData.put(PurchaseEnum.RECEIVE_STATUS.getAttr(),ReceiveStatusEnum.RECEIVED.getCode());
                }
                purchaseData.put(PurchaseEnum.STATUS.getAttr(), PurchaseStatusEnum.INSTOCK.getCode());
                JSONArray instockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(purchaseData,PurchaseEnum.INSTOCK_ID.getAttr(),new JSONArray());
                instockIdList.add(instockId);
                purchaseData.put(PurchaseEnum.INSTOCK_ID.getAttr(), instockIdList);
                if (Objects.equals(purchaseData.getLong(PurchaseEnum.RETURNED_PURCHASE_ID.getAttr()),1L)){
                    purchaseData.put(PurchaseEnum.RETURNED_PURCHASE_ID.getAttr(), BasicConstant.ZERO);
                }
                purchaseModel.update(purchaseEntityExt);
                break;
            case RED_CONTRACT_INSTOCK:
                paasFormDataEntityExt = refundModel.getByKey(refId,corpid);
                Long formId = paasFormDataEntityExt.getFormId();
                PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                Integer distributorMark = paasFormEntityExt.getDistributorMark();
                if (Objects.isNull(paasFormDataEntityExt)) {
                    return;
                }
                RefundEntityExt refundEntityExt = new RefundEntityExt();
                BeanUtil.copyProperties(paasFormDataEntityExt,refundEntityExt);
                JSONObject refundData = refundEntityExt.getData();
                //TODO
                Long refundredContractId = refundData.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
                allInBound = refundSaveHelp.judgeRefundAllInBound(instockId,refundredContractId,corpid,productSavePojoList);
                if (allInBound) {
                    refundData.put(RefundEnum.ALL_IN_BOUND.getAttr(), AllInBoundEnum.ALL_IN.getCode());
                    refundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.REFUND.getCode());
                    // 更新退货单状态
                    if (Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(),distributorMark)){
                        refundData.put(ReturnEnum.ORDER_STATUS.getAttr(), ReturnStatusEnum.COMPLETED.getCode());
                    }
                } else {
                    refundData.put(RefundEnum.ALL_IN_BOUND.getAttr(), AllInBoundEnum.NON_IN.getCode());
                    refundData.put(RefundEnum.REFUND_STATUS.getAttr(),RefundStatusEnum.PARTIAL.getCode());
                }
                instockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(refundData,RefundEnum.INSTOCK_ID.getAttr(),new JSONArray());
                instockIdList.add(instockId);
                refundData.put(RefundEnum.INSTOCK_ID.getAttr(), instockIdList);
                refundModel.update(refundEntityExt);
                break;
            case INVENTORY_INSTOCK:
                paasFormDataEntityExt = inventoryModel.getByKey(refId,corpid);
                if (Objects.isNull(paasFormDataEntityExt)) {
                    return;
                }
                InventoryEntityExt inventoryEntityExt = new InventoryEntityExt();
                BeanUtil.copyProperties(paasFormDataEntityExt,inventoryEntityExt);
                JSONObject inventoryData = inventoryEntityExt.getData();
                Integer ifLoss = inventoryData.getInteger(InventoryEnum.IF_LOSS.getAttr());
                Long outstockId = inventoryData.getLong(InventoryEnum.OUTSTOCK_ID.getAttr());
                inventoryData.put(InventoryEnum.INVENTORY_STATUS.getAttr(),InventoryNewStatusEnum.UNFINISHED.getCode());
                if (Objects.equals(ifLoss, 0)) {
                    //没有盘亏直接改状态为已出入库
                    inventoryData.put(InventoryEnum.STATUS.getAttr(), InventoryStatusEnum.ALREADY_OUT_INSTOCK.getCode());
                    inventoryData.put(InventoryEnum.INVENTORY_STATUS.getAttr(), InventoryNewStatusEnum.FINISHED.getCode());
                } else if (Objects.equals(ifLoss, 1) && !Objects.equals(outstockId, 0L)) {
                    //有盘亏但已出过库则改状态为已出入库
                    inventoryData.put(InventoryEnum.STATUS.getAttr(), InventoryStatusEnum.ALREADY_OUT_INSTOCK.getCode());
                    inventoryData.put(InventoryEnum.INVENTORY_STATUS.getAttr(), InventoryNewStatusEnum.FINISHED.getCode());
                }
                inventoryData.put(InventoryEnum.INSTOCK_ID.getAttr(), instockId);
                inventoryModel.update(inventoryEntityExt);
                break;
            case TRANSFER_INSTOCK:
                paasFormDataEntityExt = transferModel.getByKey(refId, corpid);
                if (Objects.isNull(paasFormDataEntityExt)) {
                    return;
                }
                TransferEntityExt transferEntityExt = new TransferEntityExt();
                BeanUtil.copyProperties(paasFormDataEntityExt,transferEntityExt);
                JSONObject transferData = transferEntityExt.getData();
                outstockId = transferData.getLong(TransferEnum.OUTSTOCK_ID.getAttr());
                //不需要审批状态下直接改对应单据状态
                if (!Objects.equals(outstockId, 0L)) {
                    transferData.put(TransferEnum.STATUS.getAttr(), TransferStatusEnum.ALREADY_OUT_INSTOCK.getCode());
                }
                allInBound = transferHelp.judgeTransferAllInBound(instockId,outstockId,refId,corpid,productSavePojoList);
                if (allInBound) {
                    transferData.put(TransferEnum.ALL_IN_BOUND.getAttr(), AllInBoundEnum.ALL_IN.getCode());
                    transferData.put(TransferEnum.TRANSFER_STATUS.getAttr(), TransferNewStatusEnum.TRANSFERRED.getCode());
                } else {
                    transferData.put(TransferEnum.ALL_IN_BOUND.getAttr(), AllInBoundEnum.NON_IN.getCode());
                    transferData.put(TransferEnum.TRANSFER_STATUS.getAttr(),TransferNewStatusEnum.DELIVERED.getCode());
                }
                transferData.put(TransferEnum.INSTOCK_ID.getAttr(), instockId);
                List<Long> transferIds = new ArrayList<>();
                transferIds.add(refId);
                transferHelp.updateTransferInstockNum(transferIds,corpid,productSavePojoList,null);
                transferModel.update(transferEntityExt);
                break;
            case OTHER_INSTOCK:
                break;
            case ASSEMBLE_INSTOCK:
                break;
            case FINSHED_PRODUCT_INSTOCK:
                paasFormDataEntityExt = productionOrderModel.getByKey(refId, corpid);
                if (Objects.isNull(paasFormDataEntityExt)) {
                    return;
                }
                ProductionOrderEntityExt productionOrderEntityExt = new ProductionOrderEntityExt();
                BeanUtil.copyProperties(paasFormDataEntityExt,productionOrderEntityExt);
                // 获取生产单关联的入库单
                JSONObject productionOrderData = productionOrderEntityExt.getData();
                Double alreadyInstockNum = productionOrderData.getDouble(ProductionOrderEnum.PRODUCT_INSTOCK_NUM.getAttr());
                // 成品未入库数量
                // 获取还没有入库的成品数量
                Double alreadyUnInstockNum = FastJsonHelper.getDoubleOrDefaultFromFormData(productionOrderData, ProductionOrderEnum.PRODUCT_UNINSTOCK_NUM.getAttr(), 0.00D);
                if (productSavePojoList != null && productSavePojoList.size() > 0) {
                    Double productSaveNum = 0D;
                    for (ProductSavePojo savePojo : productSavePojoList) {
                        productSaveNum += savePojo.getNum();
                    }
                    productionOrderData.put(ProductionOrderEnum.PRODUCT_INSTOCK_NUM.getAttr(), Arith.add(productSaveNum, alreadyInstockNum));
//                    if(Arith.comperaTwoDoubleByAccuracy(productSaveNum, alreadyUnInstockNum, 2)){
//                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, "输入的产品入库数量不能超过成品未入库数量");
//                    }
                    Double num = Arith.sub(alreadyUnInstockNum, productSaveNum);
                    num = num < 0 ? 0 : num;
                    productionOrderData.put(ProductionOrderEnum.PRODUCT_UNINSTOCK_NUM.getAttr(), num);
                    if (num <= StringConstant.DIFFERENCE) {
                        productionOrderData.put(ProductionOrderEnum.ALL_INCOMING.getAttr(), 1);
                    } else {
                        productionOrderData.put(ProductionOrderEnum.ALL_INCOMING.getAttr(), 0);
                    }
                }
                instockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(productionOrderData,ProductionOrderEnum.INSTOCK_ID.getAttr(),new JSONArray());
                instockIdList.add(instockId);
                productionOrderData.put(ProductionOrderEnum.INSTOCK_ID.getAttr(), instockIdList);
                productionOrderEntityExt.setData(productionOrderData);
                productionOrderModel.update(productionOrderEntityExt);
                break;
            case RETURNED_MATERIEL_INSTOCK:
                paasFormDataEntityExt = productionOrderModel.getByKey(refId,corpid);
                if (Objects.isNull(paasFormDataEntityExt)) {
                    return;
                }
                productionOrderEntityExt = new ProductionOrderEntityExt();
                BeanUtil.copyProperties(paasFormDataEntityExt,productionOrderEntityExt);
                productionOrderData = productionOrderEntityExt.getData();
                allInBound = productionOrderHelp.judgeProductionOrderAllInBound(instockId,refId,corpid,productSavePojoList);
                Integer hasReturnedMateriel = allInBound ? 0 : 1;
                productionOrderData.put(ProductionOrderEnum.HAS_RETURNED_MATERIEL.getAttr(), hasReturnedMateriel);
                productionOrderModel.update(productionOrderEntityExt);
                break;
            default:
                break;
        }
    }


    public Map<Long, ProductStockUpdateEntity> addUpdateStock(List<InstockProductEntity> instockProductList, String corpid, Boolean isFromOri) throws XbbException {
        Map<Long,ProductStockUpdateEntity> productUpdateMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Long> productIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,String> warehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, ProductStockUpdateEntity> warehouseProductUpdateMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, ProductStockUpdateEntity> batchProductUpdateMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        warehouseMap.put(0L, I18nMessageUtil.getMessage(I18nStringConstant.ALL_WAREHOUSE));
        Set<String> batchKeyList = new HashSet<>();
        Set<String> warehouseKeyList = new HashSet<>();
        for (InstockProductEntity entity : instockProductList){
            double amendNum = entity.getProductNum() == null ? 0D : entity.getProductNum();
            double amendCost = entity.getCost() == null ? 0D : entity.getCost();
            Long productId = entity.getProductId();
            String warehouseKey = productId + "_" + entity.getWarehouseId();
            warehouseKeyList.add(warehouseKey);
            // 全仓库存数据
            String allWarehouseKey = productId + "_" + 0;
            warehouseKeyList.add(allWarehouseKey);
            if (productUpdateMap.containsKey(entity.getProductId())){
                ProductStockUpdateEntity productStockUpdateEntity = productUpdateMap.get(entity.getProductId());
                productStockUpdateEntity.updateStock(amendNum,amendCost);
                productUpdateMap.put(entity.getProductId(),productStockUpdateEntity);
            }else {
                ProductStockUpdateEntity productStockUpdateEntity = new ProductStockUpdateEntity(productId,amendNum,amendCost);
                productUpdateMap.put(entity.getProductId(),productStockUpdateEntity);
            }
            //分仓
            if (warehouseProductUpdateMap.containsKey(warehouseKey)){
                ProductStockUpdateEntity productStockUpdateEntity = warehouseProductUpdateMap.get(warehouseKey);
                productStockUpdateEntity.updateStock(amendNum,amendCost);
                warehouseProductUpdateMap.put(warehouseKey,productStockUpdateEntity);
            }else {
                ProductStockUpdateEntity productStockUpdateEntity = new ProductStockUpdateEntity(warehouseKey,amendNum,amendCost);
                warehouseProductUpdateMap.put(warehouseKey,productStockUpdateEntity);
            }
            //总仓数量
            if (warehouseProductUpdateMap.containsKey(allWarehouseKey)){
                ProductStockUpdateEntity productStockUpdateEntity = warehouseProductUpdateMap.get(allWarehouseKey);
                productStockUpdateEntity.updateStock(amendNum,amendCost);
                warehouseProductUpdateMap.put(allWarehouseKey,productStockUpdateEntity);
            }else {
                ProductStockUpdateEntity productStockUpdateEntity = new ProductStockUpdateEntity(allWarehouseKey,amendNum,amendCost);
                warehouseProductUpdateMap.put(allWarehouseKey,productStockUpdateEntity);
            }
            //批次数量
            if (StringUtil.isNotEmpty(entity.getBatch())) {
                String batchKey = BatchKeyHelp.getBatchKey(productId, entity.getWarehouseId(), entity.getBatch(), entity.getProduceDate(), entity.getGuaranteePeriod());
                batchKeyList.add(batchKey);
                if (batchProductUpdateMap.containsKey(batchKey)){
                    ProductStockUpdateEntity productStockUpdateEntity = batchProductUpdateMap.get(batchKey);
                    productStockUpdateEntity.updateStock(amendNum,amendCost);
                    batchProductUpdateMap.put(batchKey,productStockUpdateEntity);
                }else {
                    ProductStockUpdateEntity productStockUpdateEntity = new ProductStockUpdateEntity(batchKey,amendNum,amendCost);
                    batchProductUpdateMap.put(batchKey,productStockUpdateEntity);
                }
            }
            //额外信息
            productIdMap.put(entity.getProductId(),entity.getParentId());
            warehouseMap.put(entity.getWarehouseId(),entity.getWarehouseName());
            if (Objects.nonNull(entity.getData())){
                warehouseMap.put(entity.getWarehouseId(),entity.getData().getString("warehouseName"));
            }
        }
        boolean insertBatchSuccess = false;
        int batchTime = 0;
        while (!insertBatchSuccess) {
            //数据库存在的key
            List<String> existBatchKeyList = productStockModel.getExistBatchKeyList(corpid,batchKeyList);
            Map<String, ProductStockUpdateEntity> copyBatchProductUpdateMap = new HashMap<>(batchProductUpdateMap.size());
            copyBatchProductUpdateMap.putAll(batchProductUpdateMap);
            //需要插入的key
            if (!batchKeyList.isEmpty()){
                List<ProductStockEntity> insertList = new ArrayList<>();
                for (String batchKey : batchKeyList){
                    if (existBatchKeyList.contains(batchKey)){
                        continue;
                    }
                    String[] batchKeyArray = batchKey.split("_");
                    Long productId = Long.valueOf(batchKeyArray[0]);
                    Long warehouseId = Long.valueOf(batchKeyArray[1]);
                    String batch = batchKeyArray[2];
                    long produceDate = 0L;
                    if (!batchKeyArray[3].isEmpty()){
                        produceDate = Long.parseLong(batchKeyArray[3]);
                    }
                    long guaranteePeriod = 0L;
                    if (!batchKeyArray[4].isEmpty()){
                        guaranteePeriod = Long.parseLong(batchKeyArray[4]);
                    }
                    ProductStockUpdateEntity productStockUpdateEntity = batchProductUpdateMap.get(batchKey);
                    ProductStockEntity productStockEntity = new ProductStockEntity();
                    productStockEntity.setId(null);
                    productStockEntity.setCorpid(corpid);
                    productStockEntity.setParentId(productIdMap.get(productId));
                    productStockEntity.setProductId(productId);
                    productStockEntity.setWarehouseId(warehouseId);
                    productStockEntity.setWarehouseName(warehouseMap.get(warehouseId));
                    productStockEntity.setBatch(batch);
                    productStockEntity.setNum(productStockUpdateEntity.getStock());
                    productStockEntity.setCost(productStockUpdateEntity.getUnitCost());
                    productStockEntity.setProduceDate(produceDate);
                    productStockEntity.setGuaranteePeriod(guaranteePeriod);
                    productStockEntity.setExpireDate(produceDate + guaranteePeriod);
                    productStockEntity.setAddTime(DateTimeUtil.getInt());
                    productStockEntity.setUpdateTime(DateTimeUtil.getInt());
                    productStockEntity.setDel(0);
                    productStockEntity.setWarehouseChecked(1);
                    productStockEntity.setBatchKey(batchKey);
                    productStockEntity.setTotalCost(Arith.mul(productStockEntity.getNum(),productStockEntity.getCost()));
                    productStockEntity.setWarehouseKey(productId + StringConstant.CROSS + warehouseId);
                    insertList.add(productStockEntity);
                    copyBatchProductUpdateMap.remove(batchKey);
                }
                if (!insertList.isEmpty()){
                    try {
                        productStockModel.insertBatch(insertList);
                        insertBatchSuccess = true;
                        batchProductUpdateMap = copyBatchProductUpdateMap;
                    } catch (DuplicateKeyException e) {
                        log.warn("==========addInstockBatchCatch:" + corpid + ",num:" + batchTime);
                        if (++batchTime > 5) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                        }
                    }
                } else {
                    break;
                }
            } else {
                break;
            }
        }
        //更新剩余的批次key
        productStockModel.updateStockDB(batchProductUpdateMap.keySet(), batchProductUpdateMap.values(),corpid);
        //需要插入的key
        Map<Long, JSONObject> warehouseIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> updateWarehouseParentIdList = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Map<Long, String>> updateWarehouseMap = new HashMap<>();
        boolean insertSuccess = false;
        int time = 0;
        while (!insertSuccess) {
            //数据库存在的key,入库时需要查询解绑warehouseChecked=0的数据
            List<ProductWarehouseEntity> existProductWarehouseList = productWarehouseModel.getExistProductWarehouseList(corpid, warehouseKeyList, null);
            Map<String, Integer> existWarehouseKeyMap = Maps.newHashMapWithExpectedSize(existProductWarehouseList.size());
            existProductWarehouseList.forEach(item -> existWarehouseKeyMap.put(item.getWarehouseKey(), item.getWarehouseChecked()));
            Map<String, ProductStockUpdateEntity> copyWarehouseProductUpdateMap = new HashMap<>(warehouseProductUpdateMap.size());
            copyWarehouseProductUpdateMap.putAll(warehouseProductUpdateMap);
            if (!warehouseKeyList.isEmpty()){
                List<ProductWarehouseEntity> insertList = new ArrayList<>();
                for (String warehouseKey : warehouseKeyList){
                    Integer warehouseChecked = existWarehouseKeyMap.get(warehouseKey);

                    String[] warehouseKeyArray = warehouseKey.split("_");
                    Long productId = Long.valueOf(warehouseKeyArray[0]);
                    Long warehouseId = Long.valueOf(warehouseKeyArray[1]);
                    // 全仓数据不需要插入，可能会有bug，以前是负库存或者总库存不为0时，不能这样算总库存
                    if (Objects.equals(warehouseId, 0L)) {
                        continue;
                    }
                    Long parentId = productIdMap.get(productId);
                    if (Objects.equals(warehouseChecked, 1)) {
                        continue;
                    }
                    // 如果没有分仓关系插入分仓关系
                    if (Objects.isNull(warehouseChecked)){
                        buildNewProductWarehouseRelation(corpid, isFromOri, warehouseMap, copyWarehouseProductUpdateMap, insertList, warehouseKey, productId, warehouseId, parentId);
                    }
                    // 1.没有分仓关系，需更新产品上的仓库
                    // 2. 有分仓关系但是被解绑了，需更新产品上的仓库
                    packageProductWarehouseName(warehouseMap, warehouseIdMap, updateWarehouseParentIdList, productId, warehouseId, parentId);
                    Map<Long, String> productWarehouseMap = updateWarehouseMap.getOrDefault(parentId,new HashMap<>());
                    productWarehouseMap.put(warehouseId,warehouseMap.get(warehouseId));
                    updateWarehouseMap.put(parentId,productWarehouseMap);
                }
                if (!insertList.isEmpty()){
                    try {
                        productWarehouseModel.insertBatchImmediately(insertList);
                        insertSuccess = true;
                        warehouseProductUpdateMap = copyWarehouseProductUpdateMap;
                    } catch (DuplicateKeyException e) {
                        log.warn("==========addInstockCatch:" + corpid + ",num:" + time);
                        if (++time > 5) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                        }
                        warehouseIdMap.clear();
                        updateWarehouseParentIdList.clear();
                        updateWarehouseMap.clear();
                    }
                } else {
                    break;
                }
            } else {
                break;
            }
        }
        //更新剩余的分仓key
        productWarehouseModel.updateStockDB(warehouseProductUpdateMap.keySet(), warehouseProductUpdateMap.values(),corpid,isFromOri);
        //更新子产品关联仓库
        productModel.updateWarehouse(warehouseIdMap.keySet(),warehouseIdMap,corpid);
        //更新子产品库存
        workflowProductHelp.updateProductStock(productUpdateMap,corpid);
        //父产品仓库更新
        if (!updateWarehouseParentIdList.isEmpty()){
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<ProductEntityExt> productEntityExtList = productModel.getProductListByIdIn(corpid,new ArrayList<>(updateWarehouseParentIdList), DelEnum.NORMAL.getDel());
            for (ProductEntityExt entityExt : productEntityExtList) {
                JSONArray parentWarehouseArray = entityExt.getData().getJSONArray(ProductEnum.WAREHOUSE.getAttr());
                JSONArray parentWarehouseNameArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(entityExt.getData(),ProductEnum.WAREHOUSE_LINK_TEXT.getAttr(),new JSONArray());
                Map<Long,String> productWarehouseMap = updateWarehouseMap.get(entityExt.getId());
                JSONObject parentData = new JSONObject();
                if (Objects.nonNull(parentWarehouseArray)) {
                    Set<Long> warehouseIdSet = new HashSet<>();
                    for (int i = 0; i < parentWarehouseArray.size(); i++) {
                        Long warehouseId = parentWarehouseArray.getLong(i);
                        warehouseIdSet.add(warehouseId);
                    }
                    productWarehouseMap.forEach((key, value) -> {
                        if (!warehouseIdSet.contains(key)) {
                            parentWarehouseArray.add(key.toString());
                            parentWarehouseNameArray.add(value);
                        }
                    });
                    parentData.put(ProductEnum.WAREHOUSE.getAttr(), parentWarehouseArray);
                    parentData.put(ProductEnum.WAREHOUSE_LINK_TEXT.getAttr(), parentWarehouseNameArray);
                } else {
                    parentData.put(ProductEnum.WAREHOUSE.getAttr(), Arrays.stream(productWarehouseMap.keySet().toArray()).map(Object::toString).toArray(String[]::new));
                    parentData.put(ProductEnum.WAREHOUSE_LINK_TEXT.getAttr(), productWarehouseMap.values().toArray());
                }
//                getNewProductWarehouseArr(productWarehouseMap, parentData, parentWarehouseArray, parentWarehouseNameArray);
                updateList.add(ExplainUtil.getUpdateData(entityExt.getId(), parentData, corpid));
            }
            if (!updateList.isEmpty()){
                productModel.updateBatch(updateList,corpid);
            }
        }
        return productUpdateMap;
    }

    /**
     * 分仓表没有的数据建立关系
     *
     * @param corpid
     * @param isFromOri
     * @param warehouseMap
     * @param copyWarehouseProductUpdateMap
     * @param updateWarehouseMap
     * @param insertList
     * @param warehouseKey
     * @param productId
     * @param warehouseId
     * @param parentId
     */
    private void buildNewProductWarehouseRelation(String corpid, Boolean isFromOri, Map<Long, String> warehouseMap, Map<String, ProductStockUpdateEntity> copyWarehouseProductUpdateMap, List<ProductWarehouseEntity> insertList, String warehouseKey, Long productId, Long warehouseId, Long parentId) {
        ProductStockUpdateEntity productStockUpdateEntity = copyWarehouseProductUpdateMap.get(warehouseKey);
        ProductWarehouseEntity productWarehouseEntity = new ProductWarehouseEntity();
        productWarehouseEntity.setId(null);
        productWarehouseEntity.setCorpid(corpid);
        productWarehouseEntity.setWarehouseId(warehouseId);
        productWarehouseEntity.setWarehouseName(warehouseMap.get(warehouseId));
        productWarehouseEntity.setProductId(productId);

        productWarehouseEntity.setParentId(parentId);
        productWarehouseEntity.setNum(productStockUpdateEntity.getStock());
        productWarehouseEntity.setCost(productStockUpdateEntity.getUnitCost());
        productWarehouseEntity.setTotalCost(Arith.mul(productStockUpdateEntity.getStock(),productStockUpdateEntity.getUnitCost()));
        productWarehouseEntity.setOriNum(0D);
        if (Objects.nonNull(isFromOri) && isFromOri) {
            productWarehouseEntity.setOriNum(productStockUpdateEntity.getStock());
        }
        productWarehouseEntity.setWarehouseChecked(1);
        productWarehouseEntity.setIsNotify(0);
        productWarehouseEntity.setStockLowerLimit(0D);
        productWarehouseEntity.setStockUpperLimit(0D);
        productWarehouseEntity.setAddTime(DateTimeUtil.getInt());
        productWarehouseEntity.setUpdateTime(DateTimeUtil.getInt());
        productWarehouseEntity.setDel(0);
        productWarehouseEntity.setWarehouseKey(warehouseKey);
        insertList.add(productWarehouseEntity);
        //移除key
        copyWarehouseProductUpdateMap.remove(warehouseKey);
    }

    /**
     * 给更新产品上的仓库关系做准备
     * @param warehouseMap
     * @param warehouseIdMap
     * @param updateWarehouseParentIdList
     * @param productId
     * @param warehouseId
     * @param parentId
     */
    private void packageProductWarehouseName(Map<Long, String> warehouseMap, Map<Long, JSONObject> warehouseIdMap, Set<Long> updateWarehouseParentIdList, Long productId, Long warehouseId, Long parentId) {
        //子产品更新仓库
        JSONObject warehouseIdEntity = warehouseIdMap.getOrDefault(productId,new JSONObject());
        String key = warehouseIdEntity.getString("key");
        String keyName = warehouseIdEntity.getString("keyName");
        String appendKey = warehouseIdEntity.getString("appendKey");
        String appendKeyName = warehouseIdEntity.getString("appendKeyName");
        StringBuilder keyBuilder = new StringBuilder();
        StringBuilder keyNameBuilder = new StringBuilder();
        StringBuilder appendKeyBuilder = new StringBuilder();
        StringBuilder appendKeyNameBuilder = new StringBuilder();
        if (StringUtil.isNotEmpty(key)){
            keyBuilder.append(key).append(",");
            keyNameBuilder.append(keyName).append(",");
            appendKeyBuilder.append(appendKey).append(",");
            appendKeyNameBuilder.append(appendKeyName).append(",");
        }
        keyBuilder.append("\"").append(warehouseId.toString()).append("\"");
        keyNameBuilder.append("\"").append(warehouseMap.getOrDefault(warehouseId, "")).append("\"");
        appendKeyNameBuilder.append("\"$.text_69\"").append(",").append("\"").append(warehouseMap.getOrDefault(warehouseId, "")).append("\"");
        appendKeyBuilder.append("\"$.text_70\"").append(",").append("\"").append(warehouseId.toString()).append("\"");
        warehouseIdEntity.put("key",keyBuilder.toString());
        warehouseIdEntity.put("keyName",keyNameBuilder.toString());
        warehouseIdEntity.put("appendKey",appendKeyBuilder.toString());
        warehouseIdEntity.put("appendKeyName",appendKeyNameBuilder.toString());
        warehouseIdMap.put(productId,warehouseIdEntity);
        //父产品更新仓库
        updateWarehouseParentIdList.add(parentId);
    }
}
